﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace VectorEditor
{
	class ResizeBox
	{
		public RectangleF Bounds { get; private set; }
		public HashSet<Primitive> PrimitiveContents { get; private set; }

		private bool isMouseDownInBounds = false;
		private float offsetX = 0.0f, offsetY = 0.0f;
		private PointF oldMousePosition;

		public ResizeBox(RectangleF bounds, HashSet<Primitive> primitives)
		{
			PrimitiveContents = primitives;
			Bounds = bounds;
		}
		public bool MouseDown(IDocumentControl control, Point mousePosition, MouseButtons button)
		{
			var docPos = control.ScreenToDocumentCoordinates(mousePosition);
			if (Bounds.Contains(docPos))
			{
				isMouseDownInBounds = true;
				oldMousePosition = docPos;
				return true;
			}
			else
			{
				isMouseDownInBounds = false;
				return false;
			}
		}
		public bool MouseUp(IDocumentControl control, Point mousePosition, MouseButtons button)
		{
			if (isMouseDownInBounds)
			{
				Bounds = new RectangleF(Bounds.X + offsetX, Bounds.Y + offsetY, Bounds.Width, Bounds.Height);
				control.Controller.PushCommand(new TransformPrimitiveCommand(PrimitiveContents, offsetX, offsetY, 1.0f, 1.0f));
				offsetX = offsetY = 0.0f;
				return true;
			}
			return false;
		}
		public bool MouseMove(IDocumentControl control, Point mousePosition, MouseButtons button)
		{
			if (isMouseDownInBounds && button == MouseButtons.Left)
			{
				var docPos = control.ScreenToDocumentCoordinates(mousePosition);
				offsetX = docPos.X - oldMousePosition.X;
				offsetY = docPos.Y - oldMousePosition.Y;
				return true;
			}
			return false;
		}

		public void Draw(Graphics g)
		{
			var pen = new Pen(Color.Gray);
			pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom;
			pen.DashPattern = new float[] { 4.0f, 2.0f };
			g.DrawRectangle(pen, Bounds.X + offsetX, Bounds.Y + offsetY, Bounds.Width, Bounds.Height);

		}

		internal Primitive ReplacePrimitive(Primitive p)
		{
			if((offsetX != 0.0f || offsetY != 0.0f) && (PrimitiveContents.Contains(p)))
			{
				var np = p.Clone();
				np.Transform(offsetX, offsetY, 1.0f, 1.0f);
				return np;
			}
			else
			{
				return p;
			}
		}
	}
	class PointerTool : Tool
	{
		HashSet<Primitive> selectedPrimitives = new HashSet<Primitive>();
		RectangleF selectionBounds;
		ResizeBox resizeBox = null;
		public override Primitive ReplacePrimitive(Primitive p)
		{
			if (resizeBox != null)
				return resizeBox.ReplacePrimitive(p);
			return base.ReplacePrimitive(p);
		}
		public override void HandleMouseDown(IDocumentControl control, Point mousePosition, MouseButtons button)
		{
			if (resizeBox != null && resizeBox.MouseDown(control, mousePosition, button))
			{
				return;
			}
			if (button == MouseButtons.Left)
			{
				var document = control.Document;
				var pDoc = control.ScreenToDocumentCoordinates(mousePosition);
				selectedPrimitives.Clear();
				foreach (var prim in document.Primitives.Reverse<Primitive>())
				{
					if (prim.HitTest(pDoc))
					{
						selectedPrimitives.Add(prim);
						break;
					}
				}

				float rectX = float.MaxValue, rectY = float.MaxValue, rectX1 = float.MinValue, rectY1 = float.MinValue;
				foreach (var prim in selectedPrimitives)
				{
					var boundingBox = prim.BoundingBox;
					rectX = Math.Min(rectX, boundingBox.X);
					rectY = Math.Min(rectY, boundingBox.Y);
					rectX1 = Math.Max(rectX1, boundingBox.Right);
					rectY1 = Math.Max(rectY1, boundingBox.Bottom);
				}
				selectionBounds = new RectangleF(rectX, rectY, rectX1 - rectX, rectY1 - rectY);

				if (selectedPrimitives.Count > 0)
				{
					resizeBox = new ResizeBox(selectionBounds, selectedPrimitives);
					resizeBox.MouseDown(control, mousePosition, button);
				}
				else
				{
					resizeBox = null;
				}
				document.FinishUpdate();
			}
			
		}

		public override void HandleMouseUp(IDocumentControl control, Point mousePosition, MouseButtons button)
		{
			if (resizeBox != null)
			{
				if (resizeBox.MouseUp(control, mousePosition, button))
					return;
			}
		}

		public override void HandleMouseMove(IDocumentControl control, Point mousePosition, MouseButtons button)
		{
			if (resizeBox != null)
			{
				if (resizeBox.MouseMove(control, mousePosition, button))
				{
					control.Document.FinishUpdate();
					return;
				}
			}
		}

		public override void DrawOverlay(Graphics g)
		{
			if (resizeBox != null)
			{
				resizeBox.Draw(g);
			}
		}
	}
}
